/*****************************************************************************************/
/* ECSE 426 - Microprocessor - Fall 2009
/* Lab Experiment 3 - Logic of the program
/* MAIN.C
/* @author: Danny Wu - 260238209 - B.Comp.Eng
/* @author: Han-Sheng Chin - 260209715 - B.Elec.Eng
/* @version: 09.10.23.1508 
/****************************************************************************************/

#include <msp430x14x.h>
#include "main.h"
#include "FreeRTOS.h"
#include "task.h"
//#include "constants.h"
//#include "uart.h"
#include "reliableTransfer.h"
#include "semphr.h" // semaphores
#include "serial.h"


int state;    // Global variable for state of the finite state machine.
int func;     // Global variable for determining which option to use in input interrupt.
int exit;     // Global variable for determining whether to exit program or not.
int input;    // Global variable to store the input values from the keyboard.
int waitInput;  // Global variable to determine if the FSM is waiting for input.
int regAdd;     // Global variable for the register address to be modified.
int regVal;     // Global variable for the new register value.
char msg[64];     // message to be transmitted
char secretCode[4];
int msgCtr;     //counter for msg length

xSemaphoreHandle xKeySemaphore = NULL;
xSemaphoreHandle xPrintSemaphore = NULL;
xSemaphoreHandle xReplySemaphore = NULL;  // for synchronisation
xSemaphoreHandle xEndGameSemaphore = NULL;  // for synchronisation
static portTASK_FUNCTION_PROTO( vMainMenu, pvParameters );
static portTASK_FUNCTION_PROTO( vEndGame, pvParameters );

int cc2500add[14] = {0x30, 0x31, 0x32, 0x33,0x34, 0x35, 0x36, 0x37,0x38, 0x39, 0x3A, 0x3B,0x3C,0x3D};
char *cc2500name[14] = {"PARTNUM", "VERSION", "FREQEST", "LQI",
"RSSI", "MARCSTATE", "WORTIME1", "WORTIME0", "PKSTATUS", "VCO_VC_DAC",
"TXBYTES", "RXBYTES", "RCCTRL1_STATUS", "RCCTRL0_STATUS"};
char *cc2500configReg[0x2F] = {"IOCFG2","IOCFG1","IOCFG0","FIFOTHR","SYNC1","SYNC0","PKTLEN","PKTCTRL1","PKTCTRL0","ADDR","CHANNR","FSCTRL1","FSCTRL0","FREQ2","FREQ1","FREQ0",
"MDMCFG4","MDMCFG3","MDMCFG2","MDMCFG1","MDMCFG0","DEVIATN","MCSM2","MCSM1","MCSM0","FOCCFG","BSCFG","AGCTRL2","AGCTRL1","AGCTRL0","WOREVT1","WOREVT0",
"WORCTRL","FREND1","FREND0","FSCAL3","FSCAL2","FSCAL1","FSCAL0","RCCTRL1","RCCTRL0","FSTEST","PTEST","AGCTEST","TEST2","TEST1","TEST0"};


/**
 * Main function
 * Used to run the logic of our program
 * -Set screenCap variable to 1 if we want to capture values from Logic Analyzer
 * *Initialize configuration of the clock
 * *Enable interrupts
 */


void main(void){
  char x;
  int i=0;
  int screenCap = 0; //capturing logic analyzer signals mode
  
  //initialize configuration of the clock
  WDTCTL = WDTPW + WDTHOLD;             // Stop WDT
  BCSCTL1 &= ~XT2OFF;                   // XT2OFF
  BCSCTL2 |= SELS;                      // MCLK = SMCLK = XT2 (safe)
  _EINT();                              // Enable interrupts
  
  vSemaphoreCreateBinary( xKeySemaphore );
  vSemaphoreCreateBinary( xPrintSemaphore );
  vSemaphoreCreateBinary( xReplySemaphore );
  vSemaphoreCreateBinary( xEndGameSemaphore );
  //capturing logic analyzer signals
  if (!screenCap) {
    initRsUART();
    initSpiUART();
    clearScreen();  
    ccResetChip();  
    ccConfigBeacon();
  } else if (screenCap) {
    ccCommandStrobe(SRES);
    spiWriteReg(PKTLEN, 0x55);
    wait(100);
    spiReadReg(SYNC0);
    exit = 1;
  } //end if

}//end main

static portTASK_FUNCTION( vMainMenu, pvParameters )
{
    for( ;; ){
      switch(state){
          case 0:     // Ready mode. Print menu and wait for user input.
            printMenu();
            func = 0;
            state = 8;  // Wait
            break;
    
          case 1:     // Dump registers mode. Print the data of all the registers.
            dumpConfigReg();
            println(""); 
            dumpStatusReg();
            println("Press ENTER for menu or ESC to exit program.");
            func = 1;
            state = 8;  // Wait
            break;
    
          case 2:     // Modify register mode. Print the data of the old value and wait for user input on new value.
            modReg();
            println("Press ENTER for menu or ESC to exit program.");
            func = 1;
            state = 8;  // Wait
            break;
    
          case 3:     // Sending and receiving data mode. Input destination and string.
            sendReceive();
            println("Press ENTER for menu or ESC to exit program.");
            func = 1;
            state = 8;  // Wait
            break;
    
          case 4:     // Receiving only mode.
            receiveOnly();
            println("Press ENTER for menu or ESC to exit program.");
            func = 1;
            state = 8;  // Wait
            break;
    
          case 5:     // Exit program.
            state = 9;
            break;
    
          case 8:     // Wait for input
            if( xSemaphoreTake( xKeySemaphore, ( portTickType ) (2000/portTICK_RATE_MS) ) == pdTRUE ) {
                //if didnt get it back yet after waiting 2 seconds loop around
            }
            break;

          case 9:
            println("Goodbye!");
            break;
        }//end switch
    }
}

static portTASK_FUNCTION( vEndGame, pvParameters )
{
    portTickType xTimeToWait = (( portTickType ) 10000/portTICK_RATE_MS); // set wait time to 10 seconds

	/* Just to stop compiler warnings. */
	( void ) pvParameters;

	for( ;; )
	{
          if( xSemaphoreTake( xEndGameSemaphore, xTimeToWait ) == pdTRUE ) { // Wait 10seconds for end game flag
                //end the game
                xEndAllHeart(); // stop all other tasks
                // reset fsm and control variables
                vTaskDelete(NULL);    // stop this task
          }
	}
}

/**
 * This function is only used to print the menu interface.
 *
 */
void printGameMenu(void) {
  clearScreen();
  println("*******************************************************************");
  println("                    Welcome to Bulls and Cows");
  println("*******************************************************************");
  println("1. Host Game.");
  println("2. Find Host.");
  println("3. CC2500 Interface.");
  println("Select an option:  ");
} //end printMenu

void printMenu(void) {
  clearScreen();
  println("*******************************************************************");
  println("Welcome to Danny & Han's CC2500 Wireless Transceiver Interface");
  println("*******************************************************************");
  println("1. Dump all registers.");
  println("2. Modify content of a register.");
  println("3. Send and receive data packets.");
  println("4. Receive data packets only.");
  println("Select an option:  ");
} //end printMenu

/**
 *  This function dumps all the configuration registers
 */
void dumpConfigReg(void) {
  char i;
  int ctr = 0;
  char *configReg[0x2F] = {"IOCFG2","IOCFG1","IOCFG0","FIFOTHR","SYNC1","SYNC0","PKTLEN","PKTCTRL1","PKTCTRL0","ADDR","CHANNR","FSCTRL1","FSCTRL0","FREQ2","FREQ1","FREQ0",
                   "MDMCFG4","MDMCFG3","MDMCFG2","MDMCFG1","MDMCFG0","DEVIATN","MCSM2","MCSM1","MCSM0","FOCCFG","BSCFG","AGCTRL2","AGCTRL1","AGCTRL0","WOREVT1","WOREVT0",
                   "WORCTRL","FREND1","FREND0","FSCAL3","FSCAL2","FSCAL1","FSCAL0","RCCTRL1","RCCTRL0","FSTEST","PTEST","AGCTEST","TEST2","TEST1","TEST0"};
  println("*****************************************");
  println("Start dumping configuration registers");
  println("*****************************************");
  println("\nADDRESS\t\tREG NAME\t\tVALUE\n");
  for(i=0x00; i < 0x2F;i++){ 
    println("");
    printHex(i);
    print("\t\t");
    print(configReg[ctr++]);
    print("    \t\t");
    printHex(spiReadReg(i));
  }//end for
  println("*****************************************");
  println("End dumping configuration registers");
  println("*****************************************");
}//end dumpConfigReg

/**
 *  This function dumps all the status registers
 */
void dumpStatusReg(void) {
  char i;
  int ctr = 0;
  char *regName[14] = {"PARTNUM  ", "VERSION  ", "FREQEST  ", "LQI     ",
                      "RSSI    ", "MARCSTATE", "WORTIME1", "WORTIME0", "PKSTATUS", "VCO_VC_DAC",
                      "TXBYTES ", "RXBYTES  ", "RCCTRL1_STATUS", "RCCTRL0_STATUS"};
  println("*****************************************");
  println("Start dumping status registers");
  println("*****************************************");
  println("\nADDRESS\t\tREG NAME\t\tVALUE\n");
  for(i=0x30; i < 0x3E;i++){ 
    println("");
    printHex(i);
    print("\t\t");
    print(regName[ctr++]);
    print("\t\t");
    printHex(spiReadReg(i));
  }//end for
  println("*****************************************");
  println("End dumping status registers");
  println("*****************************************");
}//end dumpConfigReg


void modReg(void) {
  char x;
  println("************************************************");
  println("2. Modify content of a register");
  println("************************************************");
  println("Choose desired register to be modified: 0x");
  func = 2;
  waitInput = 1;
  while (waitInput);                // Wait for input
  if (func == 2)
  {
    x = spiReadReg(regAdd);
    //if(x < 0x2F){
      println("Register name is ");   // Still have to figure out how to print register name.
      print(cc2500configReg[regAdd]);
      println(" Old value = ");                    // Still have to figure out how to print old value.
      printHex(x);
      println(" New value = 0x");
      func = 3;
      waitInput = 1;
      while (waitInput);                // Wait for input
    //}else{
      //println("Configuration address is out of bound!\n");
    //}//end if 
  } // end if
} //end modReg

/**
 * This function is used to send and receive
 *
 *
 */
void sendReceive(void) {        // Function to send and receive message.
  msgCtr = 0;
  println("************************************************");
  println("3. Print Screen and receive data packets Demo");
  println("************************************************");
  println("---Press [ENTER] to start Tasks---"); 
  //println("Enter the message to send: ");
  func = 5;
  waitInput = 1;
  /*msg[0] = 'G';  msg[1] = 'R';
  msg[2] = 'O';  msg[3] = 'U';
  msg[4] = 'P';  msg[5] = '1';
  msg[6] = '4';  msg[7] = 'b';
  msg[8] = 'e';  msg[9] = 'a';
  msg[10] = 'c'; msg[11] = 'o';
  msg[12] = 'n';*/
  //xSerialPortInitCustom( ( unsigned portBASE_TYPE ) PKT_SIZE );
  //vStartHeartTasks( ( unsigned portBASE_TYPE ) 1, ( unsigned portBASE_TYPE) 1 );
  //vTaskStartScheduler();
  while(waitInput);
  //xEndAllHeart();
  //vTaskEndScheduler();
  //send message
  //if(func == 5)ccTX(msg);}
} //end sendReceive

void receiveOnly(void) {
  println("************************************************");
  println("4. Receive data packets only");
  println("************************************************");

  ccRX();  // Code to receive data only.

} //end receiveOnly

